/*

ABINLOAD(C) CopyLeft Bill Buckels 1991-2006
All Rights Reversed.

Apple II 8K BSaved Picture Loader for the IBM-PC
Usage is        : ABINLOAD [MyPicture]

converts from prodos's BIN format to IBM BASIC's BSAVED format
and does other funky things.

Outputs a Basic BSAVED Image when no options are specified
Options         : ABINLOAD [MyPicture] COLOR
TOP & BOT       : ABINLOAD [MyPicture] TOP
TOP & BOT (save): ABINLOAD [MyPicture] TOP BIN
Saves TOP or BOT Image to PRODOS BSaved format when BIN option is specified
HIRES (default) : ABINLOAD [MyPicture] HIRES

*/

enum {  BLACK = 0,
        BLUE,
        GREEN,
        CYAN,
        RED,
        MAGENTA,
        BROWN,
        WHITE,
        GRAY,
        LBLUE,
        LGREEN,
        LCYAN,
        LRED,
        LMAGENTA,
        YELLOW,
        BWHITE,
        NUM_VGA_COLORS};

#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dos.h>
#include <io.h>
#include <fcntl.h>


/* screen modes */
#define TEXT     3
#define MED_RES  5

/* default adapter */
int ADAPTER=MED_RES;

int setcrtmode(unsigned char _CRT_MODE)
{
    union REGS rin,rout;

    if ((_bios_equiplist() & 0x30) == 0x30)
        {
        printf("Sorry... Cga Compatible Displays Only...");
         exit(0);
        }

    rin.h.ah = 0;
    rin.h.al = _CRT_MODE;
    int86(0x10,&rin,&rout);
    return 0;

}



/* a microsoft compatible bsaved image format descriptor */
char BSAVED_header[8]={
    '\xfd','\x00','\xb8','\x00','\x00','\x00','\x40','\x1a'};

void putpixel(int x, int y,int pixelvalue)
{
    union REGS inregs, outregs;

    inregs.h.ah = '\x0c';
    inregs.h.al = pixelvalue;
    inregs.x.cx = x;
    inregs.x.dx = y;

    int86(0x10, &inregs,&outregs);
}

unsigned char far *screenbuffer;
unsigned char far *binbuffer;
char far *crt = (char far *)0xb8000000l;

#ifndef S_IWRITE
#define S_IWRITE    0000200     /* write permission, owner   */
#endif

int makefile(char *filename)
{
int fh;

if((fh = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IWRITE)) == -1)
        return 0;
    write(fh,BSAVED_header,7);
    write(fh,(char *)&crt[0],0x4000);
    write(fh,(char *)&BSAVED_header[7],1);
    if(close(fh) == -1)
    return 0;
}

int makebin(char *filename)
{
int fh;

if((fh = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IWRITE)) == -1)
        return 0;

    write(fh,(char *)&binbuffer[0],0x2000);

    if(close(fh) == -1)
    return 0;
}

main(int argc, char *argv[])
{
    FILE *picture;
    char buf[66],buf2[66],buf3[66];
    int savebin = 0;

    char *wordptr;

    if(argc > 1)
    {
        screenbuffer = _fmalloc(0x2000);
        memset(screenbuffer,0,0x2000);
        strcpy(buf,argv[1]);
        wordptr=strtok(buf,".");
        sprintf(buf2,"%s.BAS",buf);
        sprintf(buf3,"%s.BIN",buf);


        binbuffer = _fmalloc(0x2000);
        memset(binbuffer,0,0x2000);

        if (argc > 2) {

			if (strcmpi(argv[2], "COLOR") == 0) {
				setcrtmode((unsigned char)0x13);
				colorpiclode(argv[1]);
			}
			else if (strcmpi(argv[2], "TOP") == 0) {
				setcrtmode((unsigned char)0x13);
				if (argc == 4) {
					if (strcmpi(argv[3], "BIN") == 0) savebin = 1;
				}
				toplode(argv[1]);
				if (savebin) makebin(buf3);
			}
			else {
				setcrtmode((unsigned char)ADAPTER);
				piclode(argv[1]);
			}
		}
		else {
		  setcrtmode((unsigned char)ADAPTER);
          piclode(argv[1]);
	    }
        getch();
        if (argc == 2)makefile(buf2);
        setcrtmode(TEXT);
        _ffree(screenbuffer);
        _ffree(binbuffer);
      }
      else {
		  puts("ABINLOAD(C) CopyLeft Bill Buckels 1991-2006\nAll Rights Reversed.");
		  puts("Apple II 8K BSaved Picture Loader for the IBM-PC");
		  puts("Usage is        : ABINLOAD [MyPicture]");
		  puts("Outputs a Basic BSAVED Image when no options are specified");
		  puts("Options         : ABINLOAD [MyPicture] COLOR");
		  puts("TOP & BOT       : ABINLOAD [MyPicture] TOP");
		  puts("TOP & BOT (save): ABINLOAD [MyPicture] TOP BIN");
		  puts("Saves TOP or BOT Image to PRODOS BSaved format when BIN option is specified");
		  puts("HIRES (default) : ABINLOAD [MyPicture] HIRES");


	  }
    exit(0);
}


piclode(name)
char *name;
{
   int fh,x,y,temp,packet=40;
   char tempchar,byte,bit;
   char linebuffer[40];

   fh = open(name,O_RDONLY|O_BINARY); /* open a binary file */

   read(fh,(char *)&screenbuffer[0],0x2000);
   close(fh);

   /* use a colored  background  */
   memset(crt,0xAA,0x4000);

   for(y=0;y<192;y++)
   {
     gethibase(y,&temp);
     memcpy(&linebuffer[0],&screenbuffer[temp],packet);
     x=0;
     for(byte=0;byte<packet;byte++)
     {
       tempchar=linebuffer[byte];
       for(bit=0;bit<7;bit++)
       {
        temp=tempchar>>bit&1;
        if(temp)putpixel(x,y,3);
        else putpixel(x,y,0);
        x++;
        }
     /* read each raster to the ibm screen */
     }
     }

}

colorpiclode(name)
char *name;
{
   int fh,x,xx,xxx,y,temp,packet=40,hoff=20, voff=4;
   unsigned char tempchar,byte,bit;
   unsigned char linebuffer[40];
   unsigned char bitbuffer[280];
   unsigned char pallettebuffer[40];
   int blue = 12, orange = 3;

   fh = open(name,O_RDONLY|O_BINARY); /* open a binary file */

   read(fh,(char *)&screenbuffer[0],0x2000);
   close(fh);

   /* use a black background  */
   memset(crt,0,0x4000);

   for(y=0;y<192;y++)
   {
     gethibase(y,&temp);
     memcpy(&linebuffer[0],&screenbuffer[temp],packet);
     x=0;
     for(byte=0;byte<packet;byte++)
     {
       tempchar=linebuffer[byte];
       for(bit=0;bit<7;bit++)
       {
        temp=tempchar>>bit&1;
        bitbuffer[x] = temp;
        x++;
        }
        pallettebuffer[byte] = (tempchar >> 7)&1;

     }
     /* read each raster to the ibm screen */
     /* set each pixel to black or white */
     for(x=0;x<280;x++) {
		 if (bitbuffer[x] == 0) putpixel(x+hoff,y+voff,BLACK);
		 else putpixel(x+hoff,y+voff,BWHITE);
	 }
	 for(x=0;x<280;x+=2) {

		     byte = x/7;

		     if (pallettebuffer[byte] == 1) {
				 blue = BLUE;
				 orange = BROWN;
			 }
			 else {
				 blue = MAGENTA;
				 orange = GREEN;
			 }

		     /* blue */
	 		 if (bitbuffer[x] == 1 && bitbuffer[x+1] == 0) {
				 putpixel(x+hoff,y+voff,blue);
				 putpixel(x+hoff+1,y+voff,blue);
		     }
	 		 /* orange */
	 		 if (bitbuffer[x] == 0 && bitbuffer[x+1] == 1) {
			 				 putpixel(x+hoff,y+voff,orange);
			 				 putpixel(x+hoff+1,y+voff,orange);
		     }

	 }

   }

}


toplode(char *name)
{
   int fh,x,xx,xxx,y,temp,height, packet, hoff, voff;
   unsigned char tempchar,byte,bit;
   int blue = 12, orange = 3;

   unsigned char bitbuffer[280];
   unsigned char pallettebuffer[40];

   fh = open(name,O_RDONLY|O_BINARY); /* open a binary file */

   read(fh,(char *)&screenbuffer[0],2);
   packet= (int)screenbuffer[0];
   height= (int)screenbuffer[1];

   hoff = (320 - (packet * 7)) / 2;
   voff = (200 - height) / 2;

   read(fh,(char *)&screenbuffer[0],(height * packet));
   close(fh);

   /* use a black background  */
   memset(crt,0,0x4000);

   for(y=0;y<height;y++)
   {

     gethibase(y,&temp);
     memcpy(&binbuffer[temp], &screenbuffer[(y*packet)],packet);
     x=0;
     for(byte=0;byte<packet;byte++)
     {
       tempchar=screenbuffer[(y*packet) + byte];
       for(bit=0;bit<7;bit++)
       {
        temp=tempchar>>bit&1;
        bitbuffer[x] = temp;
        x++;
        }
        pallettebuffer[byte] = (tempchar >> 7)&1;

     }
     /* read each raster to the ibm screen */
     /* set each pixel to black or white */
     for(x=0;x<(packet * 7);x++) {
		 if (bitbuffer[x] == 0) putpixel(x+hoff,y+voff,BLACK);
		 else putpixel(x+hoff,y+voff,BWHITE);
	 }
	 for(x=0;x<(packet * 7);x+=2) {

	         byte = x/7;

		     if (pallettebuffer[byte] == 1) {
				 blue = BLUE;
				 orange = BROWN;
			 }
			 else {
				 blue = MAGENTA;
				 orange = GREEN;
			 }
		     /* blue */
	 		 if (bitbuffer[x] == 1 && bitbuffer[x+1] == 0) {
				 putpixel(x+hoff,y+voff,blue);
				 putpixel(x+hoff+1,y+voff,blue);
		     }
	 		 /* orange */
	 		 if (bitbuffer[x] == 0 && bitbuffer[x+1] == 1) {
			 				 putpixel(x+hoff,y+voff,orange);
			 				 putpixel(x+hoff+1,y+voff,orange);
		     }

	 }

   }

}



/* provides base offset for hires scanlines         */
/* does not bother to check whether we are in range */
/* gets the address as quickly as possible          */
/* stays away from processor intensive mul and div  */

gethibase(currentline,currentbase)
int currentline;
int *currentbase;
{
  FILE *fp;
  int ybase=0,z,a;

	if(currentline >63)
	   {
	   if (currentline < 128)
	       {
		ybase+=0x28;
		currentline-=64;
	       }
	   else
	       {
	       ybase+=0x50;
	       currentline-=128;
	       }
	    }

	    z=(currentline>>3);
	    a = (z<<7)|ybase;
	    *currentbase = (currentline - (z<<3))<<10 | a;


}



